package com.szyt.basicframe.handler;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.szyt.basicframe.common.ResponseResult;
import com.szyt.basicframe.common.StatusEnum;
import com.szyt.basicframe.exceptioin.BusinessException;
import com.szyt.basicframe.pojo.entity.SysExceptionLog;
import com.szyt.basicframe.service.ISysExceptionLogService;
import com.szyt.basicframe.util.IdUtil;
import com.szyt.basicframe.util.IpUtil;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.time.LocalDateTime;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {
    @Autowired
    private ISysExceptionLogService exceptionLogService;
    private static final ObjectMapper objectMapper = new ObjectMapper();

    //参数Validation校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
//        String errorMsg = ex.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(", "));
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> {
            String fieldName = error.getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return ResponseResult.error(StatusEnum.VALIDATE_FAILED.getCode(), null, errors);
//        return ResponseEntity.badRequest().body(errors);
    }

    //处理自定义业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseResult handleBusinessException(BusinessException e){
        return ResponseResult.error(e.getCode(),e.getMessage());
    }

    // 处理认证异常、JWT过期异常
    @ExceptionHandler({AuthenticationException.class, ExpiredJwtException.class})
    public ResponseResult<String> handleAuthenticationException(AuthenticationException e) {
        return ResponseResult.error(StatusEnum.UNAUTHORIZED.getCode(), "认证失败：" + e.getMessage());
    }

    // 处理权限不足异常
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseResult<String> handleAccessDeniedException(AccessDeniedException e) {
        return ResponseResult.error(StatusEnum.FORBIDDEN.getCode(), "权限不足：" + e.getMessage());
    }

    // 处理其他未捕获异常
    @ExceptionHandler(Exception.class)
    public ResponseResult<String> handleException(Exception e, HttpServletRequest request) {
        logException(e, request, StatusEnum.INTERNAL_SERVER_ERROR.getCode());
        return ResponseResult.error(StatusEnum.INTERNAL_SERVER_ERROR.getCode(), "系统处理错误：" + e.getMessage());
    }

    /**
     * 记录异常信息到数据库
     */
    private void logException(Exception e, HttpServletRequest request, Integer statusCode) {
        try {
            SysExceptionLog log = new SysExceptionLog();
            log.setExceptionName(e.getClass().getName());
            log.setExceptionMessage(e.getMessage());
            log.setExceptionStack(getStackTraceAsString(e));
            log.setStatusCode(statusCode);
            log.setCreateTime(LocalDateTime.now());

            // 获取请求信息
            if (request != null) {
                log.setRequestUri(request.getRequestURI());
                log.setRequestMethod(request.getMethod());
                log.setIpAddress(IpUtil.getIpAddress(request));

                // 获取方法名
                HandlerMethod handlerMethod = (HandlerMethod) request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
                if (handlerMethod != null) {
                    log.setMethodName(handlerMethod.getMethod().getName());
                }
            }

            exceptionLogService.save(log);
        } catch (Exception ex) {
            // 记录异常日志失败不影响主流程
            ex.printStackTrace();
        }
    }


    /**
     * 获取异常堆栈字符串
     */
    private String getStackTraceAsString(Throwable e) {
        StringBuilder sb = new StringBuilder();
        sb.append(e.toString()).append("\n");
        for (StackTraceElement element : e.getStackTrace()) {
            sb.append("\tat ").append(element.toString()).append("\n");
        }
        return sb.toString();
    }
}
